﻿#pragma once

#include <memory>
#include "Path/Path.h"
#include "Ability/EditorAbilityViewModel.h"
#include "Framework/Tickable.h"
#include "Math/Color.h"
#include "EditorFolderAbilityViewModel.m.h"

class REditorFolderAbilityModel;
class REditorEditableTextViewModel;
class REditorPageModel;

RCLASS(ExtraHeader= ["Pages/EditorPageModel.h"])
class REditorFolderAbilityViewModel : public REditorAbilityViewModel , public ITickable
{
    ROBJECT

public:
    virtual void BindModel(TSharedObjectPtr<REditorAbilityModel> InModel) override ;
    virtual TSharedObjectPtr<RTexture2D> GetIcon() const override ;
    virtual TSharedObjectPtr<RTexture2D> GetHighlightIcon() const  override;

    TSharedObjectPtr<REditorEditableTextViewModel> GetNameEditViewModel() const { return NameEditViewModel; }
    CString GetEditingNameError() const { return EditingNameError; }
    bool HasEditingNameError() const { return !EditingNameError.IsEmpty(); }

    //is the folder ability valid (i.e. the root folder exists)
    bool IsValid() const;
    int64_t GetVisibleNodeNum() const;
    TDelegate<void> OnVisibleListSizeChanged;
    const float LineHeight=20;
    const float IconSize=16;
    const float FontSize=16;
    float GetLineOffset(int64_t Index) const;
    TSharedObjectPtr<RTexture2D> GetLineIcon(int64_t Index) const;
    CString GetVisibleNodeName(int64_t Index) const;

    //鼠标左键单击时触发，打开或关闭指定索引的文件夹
    void OnNodeClicked(int64_t Index);
    //鼠标右键单击时触发，打开右键单击的节点的上下文菜单
    void OnNodeRightMouseButtonClicked(int64_t Index);

    //上一次聚焦的文件/文件夹的索引,也就是鼠标左键单击的节点的索引
    //如果没有聚焦的文件/文件夹，返回-1
    int64_t GetFocusedNodeIndex() const;

    //上一次鼠标点击的文件/文件夹的索引，包括左键和右键
    //如果没有点击的文件/文件夹，返回-1
    int64_t GetJustClickedFileNodeIndex() const;

    //正在编辑名称的文件/文件夹的索引
    int64_t GetEditingFileNodeIndex() const;

    int64_t GetHoveredNodeIndex() const { return HoveredNodeIndex; }
    void SetHoveredNodeIndex(int64_t Index) { HoveredNodeIndex = Index; }

    TSharedObjectPtr<RTexture2D> NewFileIcon;
    void CreateFile();
    TSharedObjectPtr<RTexture2D> NewAssetFileIcon;
    void CreateAssetFile();
    TSharedObjectPtr<RTexture2D> NewFolderIcon;
    void CreateFolder();
    void Refresh();
    TSharedObjectPtr<RTexture2D> RefreshIcon;
    void CloseAllFolders();
    TSharedObjectPtr<RTexture2D> CloseAllFoldersIcon;

    void RemoveFocusedFileOrFolder();

    void RenameFocusedFileOrFolder();
protected:
    TWeakObjectPtr<REditorFolderAbilityModel> FolderModel;
    TSharedObjectPtr<RTexture2D> Icon;
    TSharedObjectPtr<RTexture2D> HighlightIcon;

    TSharedObjectPtr<RTexture2D> FolderExpendedIcon;
    TSharedObjectPtr<RTexture2D> FolderCollapsedIcon;
    TSharedObjectPtr<RTexture2D> DefaultFileIcon;

protected:
    enum class ENodeType
    {
        Folder,
        File,
        CreatingFile, //Creating file 
        CreatingFolder, //Creating folder
    };

    struct SFileSystemNode
    {
        SPath Path; //the path of the existing file or folder
        CString InputName; //the name of the file or folder that is being created
        ENodeType Type;
        bool bIsOpened= false;
        bool bIsRenaming=false;

        TSharedObjectPtr<RTexture2D> Icon;

        //the depth of the node in the tree
        int64_t Depth=0;

        //the index of the node in the visible nodes list
        //will NOT be -1, because if a file/folder is invisible, SFileSystemNode will not be created
        //(for performance reason, we don't keep invisible nodes)
        int64_t VisibleIndex=-1;
        
        TVector<std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode>> SubFolders;
 
        TVector<std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode>> SubFiles;
    
        std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode> CreatingFolderNode;

        std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode> CreatingFileNode;
    };

    //a tree containing all the visible nodes
    // cant have invisible nodes because file system is too big, may cause performance issue
    std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode> RootNode;

    //a list containing all the visible nodes
    //this list is used to display the nodes in the UI
    TVector<std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode>> NodeLists;



    //the last time the FileSystem was updated
    std::filesystem::file_time_type LastUpdateTime;
    float LastDetectTime=0; //delte time since last update

    //might be empty
    //might be invalid even if it is not empty(user might delete the folder in other software)
    SPath FocusedPath;
    //上一次左键点击的节点的索引
    int64_t LastLeftMouseClickedNodeIndex=-1;
    //上一次鼠标点击的节点的索引，包括左键和右键
    int64_t LastMouseClickedNodeIndex=-1;


    //the parent folder of the file or folder that is being created
    //once this value is not empty, will enter creating mode
    SPath CreatingParentFolder;
    //the path of the file or folder that is being renamed
    SPath RenameFileOrFolderPath;

    enum class EEditingMode
    {
        None, //not in creating mode
        CreateFile, //creating file
        CreateFolder, //creating folder
        RenameFile, //renaming file
        RenameFolder, //renaming folder
    };
    EEditingMode EditingMode= EEditingMode::None;
    std::shared_ptr<REditorFolderAbilityViewModel::SFileSystemNode> EditingNameNode;
    CString EditingNameError;

    int64_t HoveredNodeIndex=-1;

    RFUNCTION()
    void OnFrontFileChanged(TSharedObjectPtr<REditorPageModel> InFocusedPage );

    void InitializeFileSystem();

    void UpdateFileSystem();
    void UpdateIcons();

    virtual bool Tickable() override {return true;}
    virtual void Tick(float DeltaSeconds) override;

    
    TSharedObjectPtr<REditorEditableTextViewModel> NameEditViewModel;
};
